<link rel="stylesheet" href="../../node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../../node_modules/bootstrap-icons/font/bootstrap-icons.css">
<link rel="stylesheet" href="../index.css">
<div class="container-fluid" id="app">
    <div class="row pt-2">
        <div class="col">
            <div class="row">
                <div class="col">公钥：</div>
            </div>
            <div class="row">
                <div class="col">
                    <textarea class="form-control form-control-sm" v-model="publicKey" style="resize:none;color:grey" rows="8"></textarea>
                </div>
            </div>
        </div>
        <div class="col-2">
            <div class="row"><div class="col">&nbsp;</div></div>
            <div class="row">
                <div class="col">
                    <select class="form-select form-select-sm" v-model="keySize">
                        <option v-for="(key, index) in keySizeArray" :value="key.size">{{key.title}}</option>
                    </select>
                </div>
            </div>
            <div class="row mt-2">
                <div class="col text-center">
                    <button type="button" class="btn btn-secondary btn-sm form-control text-nowrap" @click="generateKey">生成密钥</button>
                </div>
            </div>
        </div>
        <div class="col">
            <div class="row">
                <div class="col">私钥：</div>
            </div>
            <div class="row">
                <div class="col">
                    <textarea class="form-control form-control-sm" v-model="privateKey" style="resize:none;color:grey" rows="8"></textarea>
                </div>
            </div>
        </div>
    </div>
    <div class="row mt-2">
        <div class="col">
            <button type="button" class="btn btn-primary btn-sm" @click="encrypt">用公钥加密下面的内容</button>
        </div>
        <div class="col">
            <button type="button" class="btn btn-primary btn-sm" @click="decrypt">用私钥解密下面的内容</button>
        </div>
        <div class="col">
            <button type="button" class="btn btn-success btn-sm" @click="sign">用私钥签名下面的内容</button>
        </div>
        <div class="col">
            <button type="button" class="btn btn-success btn-sm" @click="verify">用公钥验签下面的内容</button>
        </div>
    </div>
    <div class="row mt-2">
        <div class="col">
            <textarea class="form-control form-control-sm" v-model="content" style="resize:none;" rows="10"></textarea>
        </div>
    </div>

    <!-- 选择签名的哈希算法 -->
    <div class="modal fade" id="modalDigest" data-bs-backdrop="static">
        <div class="modal-dialog">
            <div class="modal-content">
      
                <!-- 模态框头部 -->
                <div class="modal-header">
                    <h4 class="modal-title">选择签名的哈希算法</h4>
                </div>
        
                <!-- 模态框内容 -->
                <div class="modal-body">
                    <select class="form-select form-select-sm" v-model="digest">
                        <option v-for="(digest, index) in digests" :value="digest.name">{{digest.name}}</option>
                    </select>
                </div>
        
                <!-- 模态框底部 -->
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                    <button type="button" class="btn btn-primary" id="btnSign">确认</button>
                </div>
      
            </div>
        </div>
    </div>

    <div class="modal fade" id="modalSign" data-bs-backdrop="static">
        <div class="modal-dialog">
            <div class="modal-content">
      
                <!-- 模态框头部 -->
                <div class="modal-header">
                    <h4 class="modal-title">验签内容</h4>
                </div>
        
                <!-- 模态框内容 -->
                <div class="modal-body">
                    <div class="row">
                        <div class="col">待验签名</div>
                    </div>
                    <div class="row">
                        <div class="col">
                            <textarea class="form-control form-control-sm" v-model="signature" placeholder="请输入签名" id="taSign" ref="taSign" style="resize:none" rows="8"></textarea>
                        </div>
                    </div>
                    <div class="row mt-2">
                        <div class="col">选择签名的哈希算法</div>
                    </div>
                    <div class="row">
                        <div class="col">
                            <select class="form-select form-select-sm" v-model="digest">
                                <option v-for="(digest, index) in digests" :value="digest.name">{{digest.name}}</option>
                            </select>
                        </div>
                    </div>
                </div>
        
                <!-- 模态框底部 -->
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                    <button type="button" class="btn btn-primary" id="btnVerify">确认</button>
                </div>
      
            </div>
        </div>
    </div>

    <div class="modal fade" id="verifyAlert" data-bs-backdrop="static">
        <div class="modal-dialog">
            <div class="modal-content">
      
                <!-- 模态框头部 -->
                <div class="modal-header">
                    <h4 class="modal-title">验签结果</h4>
                </div>
        
                <!-- 模态框内容 -->
                <div class="modal-body" ref="verifyResult">
                    <p>验签通过</p>
                </div>
        
                <!-- 模态框底部 -->
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary" id="btnConfirm">确认</button>
                </div>
      
            </div>
        </div>
    </div>
</div>
<script src="../../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="../../node_modules/jsencrypt/bin/jsencrypt.min.js"></script>
<script src="../../node_modules/crypto-js/crypto-js.js"></script>
<script src="../../node_modules/vue/dist/vue.global.prod.js"></script>
<script>
const app = {
    data() {
        return {
            keySizeArray: [
                { size: 512, title: '512 bit'},
                { size: 1024, title: '1024 bit'},
                { size: 2048, title: '2048 bit'},
                { size: 4096, title: '4096 bit'}
            ],
            keySize: 512,
            publicKey: '',
            privateKey: '',
            content: '',
            digest: 'md5',
            digests: [
                { method: CryptoJS.SHA256, name: 'md5'},
                { method: CryptoJS.SHA256, name: 'sha1'},
                { method: CryptoJS.SHA256, name: 'sha256'},
                { method: CryptoJS.SHA256, name: 'sha224'},
                { method: CryptoJS.SHA256, name: 'sha512'},
                { method: CryptoJS.SHA256, name: 'sha384'},
                { method: CryptoJS.SHA256, name: 'sha3'},
                { method: CryptoJS.SHA256, name: 'ripemd160'}
            ],
            signature: ''
        }
    },
    created() {
        document.addEventListener('keyup', (e) => {
            if (e.ctrlKey && e.shiftKey && (e.key == 'I' || e.key ==  'i')) {
                parent.devTools();
            }
            if (e.ctrlKey && (e.key == 'r' || e.key == 'R')) {
                parent.refresh();
            }
        });
    },
    mounted() {
        this.$refs.taSign.addEventListener('input', function() {
            let v =  document.querySelector('#taSign').value.trim()
            if(undefined == v || '' == v) {
                document.getElementById('btnVerify').disabled = true;
                return;
            }
            document.querySelector('#btnVerify').disabled = false;
        });
    },
    methods: {
        generateKey() {
            let cypher = new JSEncrypt({
                default_key_size: this.keySize
            });
            this.publicKey = cypher.getPublicKey();
            this.privateKey = cypher.getPrivateKey();
        },
        encrypt() {
            /*
             * rsa算法加密时允许的明文长度：(keySize/8-11) byte
             * 
             * 1 byte = 8 bit
             * 
             * 1 bit    = 1  二进制数据
             * 1 byte   = 8  bit
             * 1 字母    = 1  byte = 8 bit
             * 1 汉字    = 2  byte = 16 bit
             */
            if(undefined == this.publicKey || '' == this.publicKey) {
                alert('请先生成/输入公钥')
                // document.getElementsByTagName('textarea')[0].focus();
                document.querySelectorAll('textarea')[0].focus();
                return;
            }
            if(undefined == this.content || '' == this.content) {
                alert('请输入需要加密的内容')
                document.querySelectorAll('textarea')[2].focus();
                return;
            }
            let jsEncrypt = new JSEncrypt();
            jsEncrypt.setPublicKey(this.publicKey);
            this.content = jsEncrypt.encrypt(this.content)
        },
        decrypt() {
            if(undefined == this.privateKey || '' == this.privateKey) {
                alert('请先生成/输入私钥')
                document.querySelectorAll('textarea')[1].focus();
                return;
            }
            if(undefined == this.content || '' == this.content) {
                alert('请输入需要解密的内容')
                document.querySelectorAll('textarea')[2].focus();
                return;
            }
            let jsEncrypt = new JSEncrypt();
            jsEncrypt.setPublicKey(this.privateKey);
            this.content = jsEncrypt.decrypt(this.content)
        },
        sign() {
            if(undefined == this.privateKey || '' == this.privateKey) {
                alert('请先生成/输入私钥')
                document.querySelectorAll('textarea')[1].focus();
                return;
            }
            if(undefined == this.content || '' == this.content) {
                alert('请输入需要签名的内容')
                document.querySelectorAll('textarea')[2].focus();
                return;
            }
            let modal = new bootstrap.Modal(document.querySelector('#modalDigest'))
            modal.show()
            document.querySelector('#btnSign').addEventListener('click', () => {
                modal.hide()
                let d = getDigest(this.digests, this.digest)
                let jsEncrypt = new JSEncrypt();
                jsEncrypt.setPublicKey(this.privateKey);
                this.content = jsEncrypt.sign(this.content, d.method, d.name)
            })
        },
        verify() {
            if(undefined == this.publicKey || '' == this.publicKey) {
                alert('请先生成/输入公钥')
                document.querySelectorAll('textarea')[0].focus();
                return;
            }
            if(undefined == this.content || '' == this.content) {
                alert('请输入需要验签的明文')
                document.querySelectorAll('textarea')[2].focus();
                return;
            }
            let modal = new bootstrap.Modal(document.querySelector('#modalSign'))
            modal.show()
            document.querySelector('#btnVerify').addEventListener('click', () => {
                if(undefined == this.signature || '' == this.signature) {
                    this.$refs.taSign.focus();
                    return;
                }
                modal.hide()
                let d = getDigest(this.digests, this.digest)
                let jsEncrypt = new JSEncrypt();
                jsEncrypt.setPublicKey(this.publicKey);
                let result = jsEncrypt.verify(this.content, this.signature, d.method)
                let modalAlert = new bootstrap.Modal(document.querySelector('#verifyAlert'))
                if(result) {
                    // 通过
                    this.$refs.verifyResult.innerHTML = '<p>验签通过</p>'
                } else {
                    // 失败
                    this.$refs.verifyResult.innerHTML = '<p class="text-danger">验签不通过</p>'
                }
                modalAlert.show();
                document.querySelector('#btnConfirm').addEventListener('click', () => {
                    modalAlert.hide()
                })
            })
        }
    }
}
Vue.createApp(app).mount('#app');

function getDigest(digests, name) {
    let digest = '';
    for(let d of digests) {
        if(name == d.name) {
            digest = d;
            break;
        }
    }
    return digest;
}
</script>